home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / SOURCE / PPM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-19  |  13.5 KB  |  589 lines  |  [TEXT/CWIE]

  1. /****************************************************************************
  2. *                ppm.c
  3. *
  4. *  This module contains the code to read and write the PPM file format.
  5. *
  6. *  from Persistence of Vision(tm) Ray Tracer
  7. *  Copyright 1996 Persistence of Vision Team
  8. *---------------------------------------------------------------------------
  9. *  NOTICE: This source code file is provided so that users may experiment
  10. *  with enhancements to POV-Ray and to port the software to platforms other
  11. *  than those supported by the POV-Ray Team.  There are strict rules under
  12. *  which you are permitted to use this file.  The rules are in the file
  13. *  named POVLEGAL.DOC which should be distributed with this file. If
  14. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  15. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  16. *  Forum.  The latest version of POV-Ray may be found there as well.
  17. *
  18. * This program is based on the popular DKB raytracer version 2.12.
  19. * DKBTrace was originally written by David K. Buck.
  20. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  21. *
  22. * Original patch copyright 1994 Tim Rowley
  23. * Updated for POV 3.0 by Chris Cason, Jan '95.
  24. *
  25. *****************************************************************************/
  26.  
  27. /****************************************************************************
  28. *  The format is as follows:
  29. *
  30. *  (header:)
  31. *    P3              - ASCII data OR
  32. *    P6              - raw binary data
  33. *    # hello         - optional comment(s)
  34. *    wwww hhhh       - Width, Height (ASCII text)
  35. *    # world         - optional comment(s)
  36. *    nnn             - maximum color (nnn = bright, 0 = black)
  37. *
  38. *  (each pixel: one of the following)
  39. *    rr gg bb        - Red, green, blue of intensity 0-nnn (binary byte)
  40. *    RRR GGG BBB     - Red, green, blue of intensity 0-nnn (ASCII number)
  41. *
  42. *****************************************************************************/
  43.  
  44. #include "frame.h"
  45. #include "povproto.h"
  46. #include "povray.h"
  47. #include "optout.h"
  48. #include "pgm.h"
  49. #include "ppm.h"
  50.  
  51. /*****************************************************************************
  52. * Local preprocessor defines
  53. ******************************************************************************/
  54.  
  55. /*****************************************************************************
  56. * Local typedefs
  57. ******************************************************************************/
  58.  
  59. /*****************************************************************************
  60. * Local variables
  61. ******************************************************************************/
  62.  
  63. static int PPM_Line_Number;
  64.  
  65. /*****************************************************************************
  66. * Static functions
  67. ******************************************************************************/
  68.  
  69. static int Open_PPM_File PARAMS ((FILE_HANDLE *handle, char *name, int *width,
  70.                               int *height, int buffer_size, int mode));
  71. static void Write_PPM_Line PARAMS ((FILE_HANDLE *handle, COLOUR *line_data,
  72.                                     int line_number));
  73. static int Read_PPM_Line PARAMS((FILE_HANDLE *handle, COLOUR *line_data,
  74.                                  int *line_number));
  75. static void Close_PPM_File PARAMS((FILE_HANDLE *handle));
  76.  
  77. /*****************************************************************************
  78. *
  79. * FUNCTION
  80. *
  81. * INPUT
  82. *
  83. * OUTPUT
  84. *
  85. * RETURNS
  86. *
  87. * AUTHOR
  88. *
  89. * DESCRIPTION
  90. *
  91. * CHANGES
  92. *
  93. ******************************************************************************/
  94.  
  95. FILE_HANDLE *Get_PPM_File_Handle()
  96. {
  97.   FILE_HANDLE *handle;
  98.  
  99.   handle = (FILE_HANDLE *) POV_MALLOC(sizeof(FILE_HANDLE), "PPM file handle") ;
  100.  
  101.   handle->Open_File_p = Open_PPM_File;
  102.   handle->Write_Line_p = Write_PPM_Line;
  103.   handle->Read_Line_p = Read_PPM_Line;
  104.   handle->Read_Image_p = Read_PPM_Image;
  105.   handle->Close_File_p = Close_PPM_File;
  106.  
  107.   handle->file = NULL;
  108.   handle->buffer = NULL;
  109.   handle->buffer_size = 0;
  110.  
  111.   return (handle);
  112. }
  113.  
  114. /*****************************************************************************
  115. *
  116. * FUNCTION
  117. *
  118. * INPUT
  119. *   
  120. * OUTPUT
  121. *   
  122. * RETURNS
  123. *   
  124. * AUTHOR
  125. *   
  126. * DESCRIPTION
  127. *
  128. * CHANGES
  129. *
  130. ******************************************************************************/
  131.  
  132. static int Open_PPM_File(handle, name, width, height, buffer_size, mode)
  133. FILE_HANDLE *handle;
  134. char *name;
  135. int *width;
  136. int *height;
  137. int buffer_size;
  138. int mode;
  139. {
  140.   char type;
  141.   int input;
  142.   char junk[512];
  143.  
  144.   handle->mode = mode;
  145.   handle->filename = name;
  146.   PPM_Line_Number = 0;
  147.  
  148.   switch (mode)
  149.   {
  150.     case READ_MODE:
  151.  
  152.       /* We can't resume from stdout. */
  153.       if (opts.Options & TO_STDOUT  || 
  154.           (handle->file = fopen(name, READ_FILE_STRING)) == NULL)
  155.       {
  156.         Status_Info("\n");
  157.         return(0);
  158.       }
  159.  
  160.       if (buffer_size != 0)
  161.       {
  162.         handle->buffer = POV_MALLOC((size_t)buffer_size, "PPM file buffer") ;
  163.         setvbuf(handle->file, handle->buffer, _IOFBF, buffer_size);
  164.       }
  165.  
  166.       if (fscanf(handle->file, "P%c\n", &type) != 1 || type != '6')
  167.       {
  168.         return(0);
  169.       }
  170.  
  171.       /* Ignore any comments (if they are written) */
  172.  
  173.       while ((input = fgetc(handle->file)) == '#')
  174.       {
  175.         fgets(junk, 512, handle->file);
  176.       }
  177.  
  178.       ungetc(input, handle->file);
  179.  
  180.       if (fscanf(handle->file, "%d %d\n255\n", width, height) != 2)
  181.       {
  182.         return(0);
  183.       }
  184.  
  185.       Status_Info("\nResuming interrupted trace from %s",handle->filename);
  186.  
  187.       handle->width = *width;
  188.       handle->height = *height;
  189.       handle->buffer_size = buffer_size;
  190.  
  191.       break;
  192.  
  193.     case WRITE_MODE:
  194.  
  195.       if (opts.Options & TO_STDOUT)
  196.       {
  197.         buffer_size = 0;
  198.         handle->file = stdout;
  199.       }
  200.       else
  201.       {
  202.         if ((handle->file = fopen(name, WRITE_FILE_STRING)) == NULL)
  203.         {
  204.           return(0);
  205.         }
  206.       }
  207.  
  208.       if (buffer_size != 0)
  209.       {
  210.         handle->buffer = POV_MALLOC((size_t)buffer_size, "PPM file buffer") ;
  211.         setvbuf(handle->file, handle->buffer, _IOFBF, buffer_size);
  212.       }
  213.  
  214.       fprintf(handle->file, "P6\n");
  215.  
  216. #ifdef POV_COMMENTS
  217. #ifdef TRACER
  218.       fprintf(handle->file, "# Author: %s\n", TRACER);
  219. #endif
  220.  
  221.       fprintf(handle->file, "# Source: Persistence of Vision(tm) Ray Tracer v%s%s\n",
  222.               POV_RAY_VERSION, COMPILER_VER);
  223.  
  224.       if (!(opts.Options & TO_STDOUT))
  225.       {
  226.         fprintf(handle->file, "# Input File: %s\n", opts.Input_File_Name);
  227.       }
  228.  
  229.       if (opts.FrameSeq.Clock_Value != 0)
  230.       {
  231.         fprintf(handle->file, "# POV Clock: %g\n", opts.FrameSeq.Clock_Value);
  232.       }
  233.  
  234.       if (opts.Quality != 9)
  235.       {
  236.         fprintf(handle->file, "# Rendering Quality: %d\n", opts.Quality);
  237.       }
  238. #endif /* POV_COMMENTS */
  239.  
  240.       fprintf(handle->file, "%d %d\n255\n", *width, *height);
  241.  
  242.       handle->width = *width;
  243.       handle->height = *height;
  244.  
  245.       handle->buffer_size = buffer_size;
  246.  
  247.       break;
  248.  
  249.     case APPEND_MODE:
  250.  
  251.       if (opts.Options & TO_STDOUT)
  252.       {
  253.         buffer_size = 0;
  254.         handle->file = stdout;
  255.       }
  256.       else
  257.       {
  258.         if ((handle->file = fopen(name, APPEND_FILE_STRING)) == NULL)
  259.         {
  260.           return(0);
  261.         }
  262.       }
  263.  
  264.       if (buffer_size != 0)
  265.       {
  266.         handle->buffer = POV_MALLOC((size_t)buffer_size, "PPM file buffer") ;
  267.         setvbuf(handle->file, handle->buffer, _IOFBF, buffer_size);
  268.       }
  269.  
  270.       handle->buffer_size = buffer_size;
  271.  
  272.       break;
  273.   }
  274.  
  275.   return(1);
  276. }
  277.  
  278. /*****************************************************************************
  279. *
  280. * FUNCTION
  281. *
  282. * INPUT
  283. *
  284. * OUTPUT
  285. *
  286. * RETURNS
  287. *
  288. * AUTHOR
  289. *   
  290. * DESCRIPTION
  291. *
  292. * CHANGES
  293. *
  294. ******************************************************************************/
  295.  
  296. static void Write_PPM_Line(handle, line_data, line_number)
  297. FILE_HANDLE *handle;
  298. COLOUR *line_data;
  299. int line_number;
  300. {
  301.   unsigned int gray;
  302.   register int x;
  303.  
  304.   for (x = 0 ; x < handle->width ; x++)
  305.   {
  306.     if (opts.Options & HF_GRAY_16)  /* 16 bit grayscale output */
  307.     {
  308.       gray = ((0.30 * line_data[x][RED]) +
  309.               (0.59 * line_data[x][GREEN]) +
  310.               (0.11 * line_data[x][BLUE])) * 65535;
  311.  
  312.       if ((putc((gray >> 8) & 0xFF, handle->file) == EOF) ||
  313.           (putc(gray & 0xFF, handle->file) == EOF) ||
  314.           (putc(0, handle->file) == EOF))
  315.       {
  316.         Error("Error writing PPM output data to %s.\n",handle->filename);
  317.       }
  318.     }
  319.     else                            /* Normal 24 bit pixel coloring */
  320.     {
  321.       if ((putc((int)floor(line_data[x][RED] * 255.0), handle->file) == EOF) ||
  322.           (putc((int)floor(line_data[x][GREEN]*255.0), handle->file) == EOF) ||
  323.           (putc((int)floor(line_data[x][BLUE]*255.0), handle->file) == EOF))
  324.       {
  325.         Error("Error writing PPM output data to %s.\n",handle->filename);
  326.       }
  327.     }
  328.   }
  329.  
  330.   PPM_Line_Number++;
  331.  
  332.   if (handle->buffer_size == 0)
  333.   {
  334.     /* close and reopen file for integrity in case we crash */
  335.  
  336.     fflush(handle->file);
  337.  
  338.     if (!(opts.Options & TO_STDOUT))
  339.     {
  340.       handle->file = freopen(handle->filename,APPEND_FILE_STRING,handle->file);
  341.     }
  342.   }
  343. }
  344.  
  345. /*****************************************************************************
  346. *
  347. * FUNCTION
  348. *
  349. * INPUT
  350. *
  351. * OUTPUT
  352. *
  353. * RETURNS
  354. *
  355. * AUTHOR
  356. *
  357. * DESCRIPTION
  358. *
  359. * CHANGES
  360. *
  361. ******************************************************************************/
  362.  
  363. static int Read_PPM_Line(handle, line_data, line_number)
  364. FILE_HANDLE *handle;
  365. COLOUR *line_data;
  366. int *line_number;
  367. {
  368.   int data, i;
  369.  
  370.   if ((data = getc(handle->file)) == EOF)
  371.   {
  372.     return (0);
  373.   }
  374.  
  375.   ungetc(data, handle->file);
  376.  
  377.   *line_number = PPM_Line_Number++;
  378.  
  379.   for (i = 0 ; i < handle->width ; i++)
  380.   {
  381.     if ((data = getc(handle->file)) == EOF)
  382.     {
  383.       return(-1);
  384.     }
  385.  
  386.     line_data[i][RED] = (DBL) data / 255.0;
  387.  
  388.     if ((data = getc(handle->file)) == EOF)
  389.     {
  390.       return(-1);
  391.     }
  392.  
  393.     line_data[i][GREEN] = (DBL) data / 255.0;
  394.  
  395.     if ((data = getc(handle->file)) == EOF)
  396.     {
  397.       return(-1);
  398.     }
  399.  
  400.     line_data[i][BLUE] = (DBL) data / 255.0;
  401.   }
  402.  
  403.   return (1);
  404. }
  405.  
  406. /*****************************************************************************
  407. *
  408. * FUNCTION
  409. *
  410. * INPUT
  411. *
  412. * OUTPUT
  413. *
  414. * RETURNS
  415. *
  416. * AUTHOR
  417. *
  418. * DESCRIPTION
  419. *
  420. * CHANGES
  421. *
  422. ******************************************************************************/
  423.  
  424. static void Close_PPM_File(handle)
  425. FILE_HANDLE *handle;
  426. {
  427.   if (handle->file)
  428.   {
  429.     fflush(handle->file);
  430.  
  431.     /* Close and reopen file (if not stdout) for integrity in case we crash */
  432.  
  433.     if (!(opts.Options & TO_STDOUT))
  434.       fclose(handle->file);
  435.   }
  436.  
  437.   if (handle->buffer != NULL)
  438.   {
  439.     POV_FREE(handle->buffer);
  440.   }
  441.  
  442.   handle->file = NULL;
  443.   handle->buffer = NULL;
  444. }
  445.  
  446. /*****************************************************************************
  447. *
  448. * FUNCTION
  449. *
  450. * INPUT
  451. *
  452. * OUTPUT
  453. *
  454. * RETURNS
  455. *
  456. * AUTHOR
  457. *
  458. * DESCRIPTION
  459. *
  460. * CHANGES
  461. *
  462. ******************************************************************************/
  463.  
  464. void Read_PPM_Image(Image, name)
  465. IMAGE *Image;
  466. char *name;
  467. {
  468.   char type;
  469.   int width, height;
  470.   int depth;
  471.   char input;
  472.   char junk[512];
  473.   int x, y;
  474.   int data;
  475.   IMAGE_LINE *line_data;
  476.   FILE *infile;
  477.  
  478.   if ((infile = Locate_File(name, READ_FILE_STRING, ".ppm", ".PPM",TRUE)) == NULL)
  479.   {
  480.     Error("Error opening PPM image %s.\n", name);
  481.   }
  482.  
  483.   if (fscanf(infile, "P%c\n", &type) != 1 || (type != '3' && type != '6'))
  484.   {
  485.     Error ("File is not in PPM format.\n", name);
  486.   }
  487.  
  488.   /* Ignore any comments */
  489.  
  490.   while ((input = fgetc(infile)) == '#')
  491.   {
  492.     fgets(junk, 512, infile);
  493.   }
  494.  
  495.   ungetc(input, infile);
  496.  
  497.   if (fscanf(infile, "%d %d\n", &width, &height) != 2)
  498.   {
  499.     Error ("Error reading width or height from PPM image.\n", name);
  500.   }
  501.  
  502.   /* Ignore any comments */
  503.   while ((input = fgetc(infile)) == '#')
  504.   {
  505.     fgets(junk, 512, infile);
  506.   }
  507.  
  508.   ungetc(input, infile);
  509.  
  510.   if (fscanf(infile, "%d\n", &depth) != 1 || depth > 255 || depth < 1)
  511.   {
  512.     Error ("Unsupported number of colors (%d) in PPM image.\n", depth);
  513.   }
  514.  
  515.   Image->width  = (DBL)(Image->iwidth = width);
  516.   Image->height = (DBL)(Image->iheight = height);
  517.  
  518.   Image->Colour_Map_Size = 0;
  519.  
  520.   Image->Colour_Map = NULL;
  521.  
  522.   Image->data.rgb_lines = (IMAGE_LINE *) POV_MALLOC(Image->iheight * sizeof (IMAGE_LINE), "PPM image");
  523.  
  524.   for (y = 0; y < height; y++)
  525.   {
  526.     line_data = &Image->data.rgb_lines[y];
  527.  
  528.     line_data->red   = (unsigned char *)POV_MALLOC(width,"PPM image line");
  529.     line_data->green = (unsigned char *)POV_MALLOC(width,"PPM image line");
  530.     line_data->blue  = (unsigned char *)POV_MALLOC(width,"PPM image line");
  531.     line_data->transm = (unsigned char *)NULL;
  532.  
  533.     if (type == '3') /* ASCII data to be input */
  534.     {
  535.       for (x = 0; x < width; x++)
  536.       {
  537.         if (fscanf(infile,"%d",&data) != 1)
  538.         {
  539.           Error("Error reading data from PPM image.\n");
  540.         }
  541.  
  542.         line_data->red[x] = data*255/depth;
  543.  
  544.         if (fscanf(infile,"%d",&data) != 1)
  545.         {
  546.           Error("Error reading data from PPM image.\n");
  547.         }
  548.  
  549.         line_data->green[x] = data*255/depth;
  550.  
  551.         if (fscanf(infile,"%d",&data) != 1)
  552.         {
  553.           Error("Error reading data from PPM image.\n");
  554.         }
  555.  
  556.         line_data->blue[x] = data*255/depth;
  557.       }
  558.     }
  559.     else /* (type == '6') Raw binary data to be input */
  560.     {
  561.       for (x = 0; x < width; x++)
  562.       {
  563.         if ((data = getc(infile)) == EOF)
  564.         {
  565.           Error("Error reading data from PPM image.\n");
  566.         }
  567.  
  568.         line_data->red[x] = data*255/depth;
  569.  
  570.         if ((data = getc(infile)) == EOF)
  571.         {
  572.           Error("Error reading data from PPM image.\n");
  573.         }
  574.  
  575.         line_data->green[x] = data*255/depth;
  576.  
  577.         if ((data = getc(infile)) == EOF)
  578.         {
  579.           Error("Error reading data from PPM image.\n");
  580.         }
  581.  
  582.         line_data->blue[x] = data*255/depth;
  583.       }
  584.     }
  585.   }
  586.  
  587.   fclose(infile);
  588. }
  589.